import json
import uuid
import time
from dataclasses import dataclass, field
from threading import Lock
from typing import Optional, List, Dict, Any

@dataclass
class Peer:
    user_id: str
    room_id: str
    offer: Optional[Dict[str, Any]] = None
    answer: Optional[Dict[str, Any]] = None
    ice_candidates: Optional[List[Dict[str, Any]]] = field(default_factory=list)
    connection_established: bool = False  # 新增：连接状态标志
    processed_offers: set = field(default_factory=set)  # 新增：已处理的offer
    processed_answers: set = field(default_factory=set)  # 新增：已处理的answer
    last_activity: float = field(default_factory=time.time)  # 新增：最后活动时间
    created_time: float = field(default_factory=time.time)  # 新增：创建时间

class Room:
    def __init__(self, room_id):
        self.room_id = room_id
        self.peers = {}  # user_id -> Peer
        self.created_time = time.time()  # 新增：房间创建时间
        
    def add_peer(self, peer):
        self.peers[peer.user_id] = peer
        
    def remove_peer(self, user_id):
        if user_id in self.peers:
            del self.peers[user_id]
            
    def get_peer(self, user_id):
        return self.peers.get(user_id)
        
    def get_other_peers(self, user_id):
        return {uid: peer for uid, peer in self.peers.items() if uid != user_id}
        
    def is_empty(self):
        return len(self.peers) == 0
    
    def update_peer_activity(self, user_id):
        """更新用户活动时间"""
        if user_id in self.peers:
            self.peers[user_id].last_activity = time.time()

class WebRTCHandler:
    def __init__(self):
        self.peers = {}  # user_id -> Peer
        self.rooms = {}  # room_id -> Room
        self.lock = Lock()
        self.cleanup_interval = 300  # 5分钟清理一次
        self.peer_timeout = 600  # 10分钟无活动则清理
        self.room_timeout = 1800  # 30分钟无活动则清理房间
        self.last_cleanup = time.time()

    def _cleanup_inactive_peers_and_rooms(self):
        """清理不活跃的用户和房间"""
        current_time = time.time()
        
        # 每5分钟执行一次清理
        if current_time - self.last_cleanup < self.cleanup_interval:
            return
            
        with self.lock:
            print(f"开始清理检查 - 当前时间: {time.strftime('%Y-%m-%d %H:%M:%S')}")
            print(f"当前状态: {len(self.peers)}个用户, {len(self.rooms)}个房间")
            
            # 清理不活跃的用户
            inactive_peers = []
            for user_id, peer in self.peers.items():
                inactive_time = current_time - peer.last_activity
                if inactive_time > self.peer_timeout:
                    inactive_peers.append(user_id)
                    print(f"检测到不活跃用户: {user_id}, 无活动时间: {int(inactive_time)}秒")
            
            # 记录需要清理的房间
            rooms_to_check = set()
            
            # 清理不活跃的用户
            for user_id in inactive_peers:
                if user_id in self.peers:
                    peer = self.peers[user_id]
                    room_id = peer.room_id
                    
                    print(f"清理不活跃用户: {user_id}, 所在房间: {room_id}")
                    
                    # 重置peer状态
                    self.reset_peer_state(peer)
                    
                    # 从房间中移除
                    if room_id in self.rooms:
                        self.rooms[room_id].remove_peer(user_id)
                        rooms_to_check.add(room_id)
                        
                        # 重置房间内其他peer的状态
                        for other_peer in self.rooms[room_id].peers.values():
                            print(f"重置房间 {room_id} 中用户 {other_peer.user_id} 的状态")
                            self.reset_peer_state(other_peer)
                    
                    # 从全局peers中删除
                    del self.peers[user_id]
            
            # 清理空房间和长时间无活动的房间
            inactive_rooms = []
            for room_id, room in self.rooms.items():
                room_inactive_time = current_time - room.created_time
                if room.is_empty() or (room_inactive_time > self.room_timeout and len(room.peers) == 0):
                    inactive_rooms.append(room_id)
                    print(f"标记待清理房间: {room_id}, 存在时间: {int(room_inactive_time)}秒, 用户数: {len(room.peers)}")
            
            # 清理房间
            for room_id in inactive_rooms:
                if room_id in self.rooms:
                    # 确保房间内所有peer都被正确清理
                    for peer in list(self.rooms[room_id].peers.values()):
                        user_id = peer.user_id
                        if user_id in self.peers:
                            print(f"清理房间 {room_id} 中遗留的用户 {user_id}")
                            self.reset_peer_state(peer)
                            del self.peers[user_id]
                    
                    print(f"清理房间: {room_id}")
                    del self.rooms[room_id]
            
            self.last_cleanup = current_time
            print(f"清理完成 - 剩余: {len(self.peers)}个用户, {len(self.rooms)}个房间")

    def _update_peer_activity(self, user_id):
        """更新用户活动时间"""
        if user_id in self.peers:
            self.peers[user_id].last_activity = time.time()
            if self.peers[user_id].room_id in self.rooms:
                self.rooms[self.peers[user_id].room_id].update_peer_activity(user_id)

    def create_or_join_room(self, room_id=None):
        """创建新房间或加入现有房间"""
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            # 生成唯一的用户ID
            user_id = str(uuid.uuid4())
            
            # 如果没有提供room_id，创建新房间
            if not room_id:
                room_id = str(uuid.uuid4())
                self.rooms[room_id] = Room(room_id)
            # 如果提供了room_id但不存在，创建新房间
            elif room_id not in self.rooms:
                self.rooms[room_id] = Room(room_id)
                
            return room_id, user_id
        
    def handle_offer(self, offer_data):
        """处理offer并存储"""
        self._cleanup_inactive_peers_and_rooms()
        
        room_id = offer_data.get('room_id')
        user_id = offer_data.get('user_id')
        offer = offer_data.get('offer')
        force_reset = offer_data.get('force_reset', False)  # 新增：强制重置标志
        
        if not offer or not room_id or not user_id:
            return {'error': 'Missing required fields'}, 400
            
        with self.lock:
            # 检查房间是否存在，不存在则创建
            if room_id not in self.rooms:
                self.rooms[room_id] = Room(room_id)
                
            # 检查用户是否已存在
            if user_id in self.peers:
                peer = self.peers[user_id]
                current_time = time.time()
                
                # 检查是否需要重置连接状态
                connection_timeout = current_time - peer.last_activity > 60  # 1分钟无活动视为超时
                
                # 如果强制重置或连接超时，重置peer状态
                if force_reset or connection_timeout:
                    print(f"重置用户 {user_id} 的连接状态")
                    self.reset_peer_state(peer)
                # 如果连接已建立且未超时，拒绝重复的offer
                elif peer.connection_established:
                    return {
                        'status': 'connection_already_established',
                        'message': '连接已建立，无需重复发送offer'
                    }
                
                # 如果offer已处理过且未重置，拒绝重复处理
                offer_hash = hash(f"{offer.get('sdp', '')}{offer.get('type', '')}")
                if not force_reset and not connection_timeout and offer_hash in peer.processed_offers:
                    return {
                        'status': 'offer_already_processed',
                        'message': 'Offer已处理过'
                    }
                
                # 标记offer为已处理
                peer.processed_offers.add(offer_hash)
                # 更新offer
                peer.offer = offer
                self._update_peer_activity(user_id)
                return {
                    'status': 'offer_updated',
                    'message': 'Offer已更新'
                }
                
            # 创建新的peer并添加到房间
            peer = Peer(
                user_id=user_id,
                room_id=room_id,
                offer=offer,
                ice_candidates=[]
            )
            # 标记offer为已处理
            offer_hash = hash(f"{offer.get('sdp', '')}{offer.get('type', '')}")
            peer.processed_offers.add(offer_hash)
            
            self.peers[user_id] = peer
            self.rooms[room_id].add_peer(peer)
            
            # 获取房间内其他用户数量
            other_peers = self.rooms[room_id].get_other_peers(user_id)
            
            if other_peers:
                # 如果有其他用户，返回成功状态
                return {
                    'status': 'offer_sent',
                    'user_id': user_id,
                    'room_id': room_id,
                    'message': f'Offer已发送，房间内有{len(other_peers)}个其他用户'
                }
            else:
                # 如果没有其他用户，返回等待状态
                return {
                    'status': 'waiting_for_peer',
                    'user_id': user_id,
                    'room_id': room_id,
                    'message': '等待其他用户加入房间'
                }
        
    def handle_answer(self, answer_data):
        """处理answer并转发给对应的用户"""
        self._cleanup_inactive_peers_and_rooms()
        
        user_id = answer_data.get('user_id')
        room_id = answer_data.get('room_id')
        answer = answer_data.get('answer')
        force_reset = answer_data.get('force_reset', False)  # 新增：强制重置标志
        
        if not answer or not user_id or not room_id:
            return {'error': 'Missing required fields'}, 400
            
        with self.lock:
            # 检查房间是否存在
            if room_id not in self.rooms:
                return {'error': 'Room not found'}, 404
                
            # 如果用户不存在，创建新的peer（被叫方的情况）
            if user_id not in self.peers:
                peer = Peer(
                    user_id=user_id,
                    room_id=room_id,
                    offer=None,
                    ice_candidates=[]
                )
                self.peers[user_id] = peer
                self.rooms[room_id].add_peer(peer)
            
            peer = self.peers[user_id]
            current_time = time.time()
            
            # 检查是否需要重置连接状态
            connection_timeout = current_time - peer.last_activity > 60  # 1分钟无活动视为超时
            
            # 如果强制重置或连接超时，重置peer状态
            if force_reset or connection_timeout:
                print(f"重置用户 {user_id} 的连接状态 (answer处理)")
                self.reset_peer_state(peer)
            # 如果连接已建立且未超时，拒绝重复的answer
            elif peer.connection_established:
                return {
                    'status': 'connection_already_established',
                    'message': '连接已建立，无需重复发送answer'
                }
            
            # 如果answer已处理过且未重置，拒绝重复处理
            answer_hash = hash(f"{answer.get('sdp', '')}{answer.get('type', '')}")
            if not force_reset and not connection_timeout and answer_hash in peer.processed_answers:
                return {
                    'status': 'answer_already_processed',
                    'message': 'Answer已处理过'
                }
            
            # 标记answer为已处理
            peer.processed_answers.add(answer_hash)
            peer.answer = answer
            peer.connection_established = True  # 明确标记连接已建立
            self._update_peer_activity(user_id)
            
            # 获取房间内其他用户
            other_peers = self.rooms[room_id].get_other_peers(user_id)
            
            # 返回给其他用户的answer
            if other_peers:
                other_user_id = list(other_peers.keys())[0]
                return {
                    'status': 'answer_received',
                    'user_id': user_id,
                    'room_id': room_id,
                    'answer': answer,
                    'target_user_id': other_user_id
                }
            
        return {
            'status': 'answer_received',
            'user_id': user_id,
            'room_id': room_id,
            'answer': answer
        }
        
    def handle_ice_candidate(self, candidate_data):
        """处理ICE候选并转发给房间内其他用户"""
        self._cleanup_inactive_peers_and_rooms()
        
        user_id = candidate_data.get('user_id')
        room_id = candidate_data.get('room_id')
        candidate = candidate_data.get('candidate')
        force_reset = candidate_data.get('force_reset', False)  # 新增：强制重置标志
        
        if not candidate or not user_id or not room_id:
            return {'error': 'Missing required fields'}, 400
            
        with self.lock:
            # 检查房间是否存在
            if room_id not in self.rooms:
                return {'error': 'Room not found'}, 404
                
            # 如果用户不存在，创建新的peer（被叫方的情况）
            if user_id not in self.peers:
                peer = Peer(
                    user_id=user_id,
                    room_id=room_id,
                    offer=None,
                    ice_candidates=[]
                )
                self.peers[user_id] = peer
                self.rooms[room_id].add_peer(peer)
                
            # 添加ICE候选
            peer = self.peers[user_id]
            current_time = time.time()
            
            # 检查是否需要重置连接状态
            connection_timeout = current_time - peer.last_activity > 60  # 1分钟无活动视为超时
            
            # 如果强制重置或连接超时，重置peer状态
            if force_reset or connection_timeout:
                print(f"重置用户 {user_id} 的连接状态 (ICE处理)")
                self.reset_peer_state(peer)
            
            # 检查是否重复的ICE候选
            candidate_str = f"{candidate.get('candidate', '')}{candidate.get('sdpMid', '')}{candidate.get('sdpMLineIndex', '')}"
            if not force_reset and not connection_timeout and any(candidate_str == f"{c.get('candidate', '')}{c.get('sdpMid', '')}{c.get('sdpMLineIndex', '')}" for c in peer.ice_candidates):
                return {
                    'status': 'ice_candidate_duplicate',
                    'message': 'ICE候选已存在'
                }
            
            # 添加新的ICE候选
            peer.ice_candidates.append(candidate)
            self._update_peer_activity(user_id)
            
            # 获取房间内其他用户的ICE候选
            other_peers = self.rooms[room_id].get_other_peers(user_id)
            other_candidates = {}
            
            for uid, p in other_peers.items():
                if p.ice_candidates and len(p.ice_candidates) > 0:
                    other_candidates[uid] = p.ice_candidates
            
        return {
            'status': 'ice_candidate_received',
            'user_id': user_id,
            'room_id': room_id,
            'other_candidates': other_candidates
        }

    def mark_connection_established(self, user_id, room_id):
        """标记连接已建立"""
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            if user_id in self.peers:
                self.peers[user_id].connection_established = True
                self._update_peer_activity(user_id)
                return {'status': 'connection_marked_established'}
            return {'error': 'User not found'}, 404

    def get_connection_status(self, user_id):
        """获取连接状态"""
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            if user_id in self.peers:
                self._update_peer_activity(user_id)
                return {
                    'connection_established': self.peers[user_id].connection_established,
                    'has_offer': self.peers[user_id].offer is not None,
                    'has_answer': self.peers[user_id].answer is not None,
                    'ice_candidates_count': len(self.peers[user_id].ice_candidates)
                }
            return {'error': 'User not found'}, 404

    def get_peer(self, user_id):
        """获取peer信息"""
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            if user_id in self.peers:
                self._update_peer_activity(user_id)
            return self.peers.get(user_id)
            
    def get_room_peers(self, room_id):
        """获取房间内所有用户"""
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            if room_id not in self.rooms:
                return {}
            return self.rooms[room_id].peers
            
    def reset_peer_state(self, peer):
        """重置peer的状态"""
        peer.offer = None
        peer.answer = None
        peer.ice_candidates = []
        peer.connection_established = False
        peer.processed_offers = set()
        peer.processed_answers = set()
        peer.last_activity = time.time()
        
    def leave_room(self, user_id, room_id):
        """用户离开房间"""
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            if room_id in self.rooms:
                room = self.rooms[room_id]
                # 在移除peer之前重置其状态
                if user_id in room.peers:
                    self.reset_peer_state(room.peers[user_id])
                room.remove_peer(user_id)
                
                # 重置房间内其他peer的状态
                for peer in room.peers.values():
                    self.reset_peer_state(peer)
                
                # 如果房间为空，删除房间
                if room.is_empty():
                    del self.rooms[room_id]
                    
            # 从全局peers中删除
            if user_id in self.peers:
                del self.peers[user_id]
                
        return {'status': 'left_room', 'user_id': user_id, 'room_id': room_id}
    
    def get_room_offers(self, room_id):
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            if room_id not in self.rooms:
                return {}
            return {uid: peer.offer for uid, peer in self.rooms[room_id].peers.items() if peer.offer}

    def get_room_answers(self, room_id):
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            if room_id not in self.rooms:
                return {}
            return {uid: peer.answer for uid, peer in self.rooms[room_id].peers.items() if peer.answer}

    def get_room_candidates(self, room_id):
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            if room_id not in self.rooms:
                return {}
            return {uid: peer.ice_candidates for uid, peer in self.rooms[room_id].peers.items() if peer.ice_candidates}
    
    def get_stats(self):
        """获取服务器统计信息"""
        self._cleanup_inactive_peers_and_rooms()
        
        with self.lock:
            return {
                'total_peers': len(self.peers),
                'total_rooms': len(self.rooms),
                'connected_peers': len([p for p in self.peers.values() if p.connection_established]),
                'uptime': time.time() - self.last_cleanup + self.cleanup_interval
            }